/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    spi.c
 * @brief   This file provides code for the configuration
 *          of the SPI instances.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi2;

/* SPI2 init function */
void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
  /*设置默认电平*/
  MySPI_Stop();   // SPI终止
  MySPI_W_SCK(0); // SCK默认低电平
  /* USER CODE END SPI2_Init 2 */

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GYRO_SCK_Pin|GYRO_MISO_Pin|GYRO_MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspDeInit 0 */

  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();

    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GYRO_SCK_Pin|GYRO_MISO_Pin|GYRO_MOSI_Pin);

  /* USER CODE BEGIN SPI2_MspDeInit 1 */

  /* USER CODE END SPI2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/*引脚配置层*/

/**
 * 函    数：SPI写SS引脚电平
 * 参    数：BitValue 协议层传入的当前需要写入SS的电平，范围0~1
 * 返 回 值：无
 * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置SS为低电平，当BitValue为1时，需要置SS为高电平
 */
void MySPI_W_SS(uint8_t BitValue)
{
  HAL_GPIO_WritePin(GYRO_CS_GPIO_Port, GYRO_CS_Pin, (GPIO_PinState)BitValue); // 根据BitValue，设置SS引脚的电平
}

/**
 * 函    数：SPI写SCK引脚电平
 * 参    数：BitValue 协议层传入的当前需要写入SCK的电平，范围0~1
 * 返 回 值：无
 * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置SCK为低电平，当BitValue为1时，需要置SCK为高电平
 */
void MySPI_W_SCK(uint8_t BitValue)
{
  HAL_GPIO_WritePin(GYRO_SCK_GPIO_Port, GYRO_SCK_Pin, (GPIO_PinState)BitValue); // 根据BitValue，设置SCK引脚的电平
}

/**
 * 函    数：SPI写MOSI引脚电平
 * 参    数：BitValue 协议层传入的当前需要写入MOSI的电平，范围0~0xFF
 * 返 回 值：无
 * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置MOSI为低电平，当BitValue非0时，需要置MOSI为高电平
 */
void MySPI_W_MOSI(uint8_t BitValue)
{
  HAL_GPIO_WritePin(GYRO_MOSI_GPIO_Port, GYRO_MOSI_Pin, (GPIO_PinState)BitValue); // 根据BitValue，设置MOSI引脚的电平，BitValue要实现非0即1的特性
}

/**
 * 函    数：I2C读MISO引脚电平
 * 参    数：无
 * 返 回 值：协议层需要得到的当前MISO的电平，范围0~1
 * 注意事项：此函数需要用户实现内容，当前MISO为低电平时，返回0，当前MISO为高电平时，返回1
 */
uint8_t MySPI_R_MISO(void)
{
  return HAL_GPIO_ReadPin(GYRO_MISO_GPIO_Port, GYRO_MISO_Pin); // 读取MISO电平并返回
}

/**
 * 函    数：SPI初始化
 * 参    数：无
 * 返 回 值：无
 * 注意事项：此函数需要用户实现内容，实现SS、SCK、MOSI和MISO引脚的初始化
 */

/*协议层*/

/**
 * 函    数：SPI起始
 * 参    数：无
 * 返 回 值：无
 */
void MySPI_Start(void)
{
  MySPI_W_SS(0); // 拉低SS，开始时序
}

/**
 * 函    数：SPI终止
 * 参    数：无
 * 返 回 值：无
 */
void MySPI_Stop(void)
{
  MySPI_W_SS(1); // 拉高SS，终止时序
}

/**
 * 函    数：SPI交换传输一个字节，使用SPI模式0
 * 参    数：ByteSend 要发送的一个字节
 * 返 回 值：接收的一个字节
 */
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
  uint8_t i, ByteReceive = 0x00; // 定义接收的数据，并赋初值0x00，此处必须赋初值0x00，后面会用到

  for (i = 0; i < 8; i++) // 循环8次，依次交换每一位数据
  {
    MySPI_W_MOSI(ByteSend & (0x80 >> i)); // 使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线
    MySPI_W_SCK(1);                       // 拉高SCK，上升沿移出数据
    if (MySPI_R_MISO() == 1)
    {
      ByteReceive |= (0x80 >> i);
    } // 读取MISO数据，并存储到Byte变量
    // 当MISO为1时，置变量指定位为1，当MISO为0时，不做处理，指定位为默认的初值0
    MySPI_W_SCK(0); // 拉低SCK，下降沿移入数据
  }

  return ByteReceive; // 返回接收到的一个字节数据
}

/* USER CODE END 1 */
